#include "EventLoop.h"
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include "TcpConnection.h"
//初始化
struct EventLoop* eventLoopInit()
{
    return eventLoopInitEx(NULL);
}
//写数据
void taskWakeup(struct EventLoop* evLoop)
{
    const char* msg = "WAKE_UP";
    write(evLoop->socketPair[0], msg, strlen(msg));
}
//读数据
int ReadLocalMsg(void * arg)
{
    struct EventLoop* ev = (struct EventLoop*)arg;
    char buf[20] = { 0 };
    read(ev->socketPair[1], buf, sizeof(buf));
    return 0;
}

struct EventLoop* eventLoopInitEx(const char* threadName)
{
    struct EventLoop* evLoop = (struct EventLoop*)malloc(sizeof(struct EventLoop));
    evLoop->isQuit = false;
    evLoop->threadID = pthread_self();
    pthread_mutex_init(&evLoop->mutex, NULL);
    strcpy(evLoop->threadName, threadName == NULL ? "MainTHread" : threadName);
    evLoop->dispatcher = &EpollDispatcher;
    evLoop->dispatcherData = evLoop->dispatcher->init();
    //链表
    evLoop->head = evLoop->tail =  NULL;
    //map
    evLoop->channelMap = channelMapInit(128);
    //mutex
    pthread_mutex_init(&evLoop->mutex, NULL);
    //AF_UNIX本地通信，用于唤醒事件循环的套接字。
    int ret = socketpair(AF_UNIX, SOCK_STREAM, 0, evLoop->socketPair);
    if(ret == -1)
    {
        perror("socketpair");
        exit(0);
    }
    //创建一个本地唤醒的套接字Channel
    //指定规则:evloop->socketPair[0]发送数据，evLoop->socketPair[1]接收数据
    struct Channel* channel = channelInit(evLoop->socketPair[1], ReadEvent, 
    ReadLocalMsg, NULL, NULL, evLoop);
    //channel添加到任务队列
    eventLoopAddTask(evLoop, channel, ADD);
    return evLoop;
}

//启动反应堆模型
int eventLoopRun(struct EventLoop* evLoop)
{
    assert(evLoop != NULL);
    //取出事件分发和检测模型
    struct Dispatcher* dispatcher = evLoop->dispatcher;
    //比较线程ID是否正常
    if(evLoop->threadID != pthread_self())
    {
        return -1;
    }
    //循环进行事件处理
    while(!evLoop->isQuit)
    {
        dispatcher->dispatch(evLoop, 2);    //超时时长2s
        eventLoopProcessTask(evLoop);//处理任务队列的任务
    }
    return 0;
}

//处理被激活的文件fd
int eventActivate(struct EventLoop* evLoop, int fd, int event)
{
    if(fd < 0 || evLoop == NULL)
    {
        return -1;
    }
    //取出channel
    struct Channel* channel = evLoop->channelMap->list[fd];
    assert(channel->fd == fd);//检测一下
    if(event & ReadEvent && (channel->readCallBack != NULL))//读事件
    {
        channel->readCallBack(channel->arg);
    }
    if(event & WriteEvent && (channel->writeCallBack != NULL))//写事件
    {
        channel->writeCallBack(channel->arg);
    }
    return 0;
}

//添加任务到任务队列
int eventLoopAddTask(struct EventLoop* evLoop, struct Channel* channel, int type)
{
    //加锁,保护共享资源
    pthread_mutex_lock(&evLoop->mutex);
    //创建新节点
    struct ChannelElement* node = (struct ChannelElement*)malloc(sizeof(struct ChannelElement));
    node->channel = channel;
    node->type = type;
    node->next = NULL;
    //链表为空
    if(evLoop->head == NULL)
    {
        evLoop->head = evLoop->tail = node;
    }
    else
    {
        evLoop->tail->next = node;
        evLoop->tail = node;
    }
    pthread_mutex_unlock(&evLoop->mutex);
    //处理节点
    //1.对于链表节点的添加：可能是当前线程也可能是其他线程（主线程）
    //    1）.修改fd的事件，当前子线程发起，当前子线程处理
    //    2）.添加新的fd，添加任务节点的操作是由主线程发起的
    //2.不能让主线程处理任务队列，需要由当前的子线程去处理
    if(evLoop->threadID == pthread_self())
    {
        //当前子线程
        eventLoopProcessTask(evLoop);
    }  
    else
    {
        //主线程 -- 通知子线程处理任务队列的任务
        //1.子线程在工作 2.子线程被阻塞了：select、poll、epoll
        taskWakeup(evLoop);
    }

    return 0;
}

//处理任务队列中的任务
int eventLoopProcessTask(struct EventLoop* evLoop)
{
    pthread_mutex_lock(&evLoop->mutex);
    //取出头节点
    struct ChannelElement* travel = evLoop->head;

    while(travel != NULL)
    {
        struct Channel* channel = travel->channel;
        if(travel->type == ADD)
        {
            //添加
            eventLoopAdd(evLoop, channel);
        }
        else if(travel->type == DELETE)
        {
            //删除
            eventLoopRemove(evLoop, channel);
        }
        if(travel->type == MODIFY)
        {
            //修改
            eventLoopModify(evLoop, channel);
        }
        struct ChannelElement* tmp = travel;
        travel = travel->next;
        free(tmp);
    }
    evLoop->head = evLoop->tail = NULL;
    pthread_mutex_unlock(&evLoop->mutex);

    return 0;
}

//处理dispatcher中的节点
//添加channel
int eventLoopAdd(struct EventLoop* evLoop, struct Channel* channel)
{
    int fd = channel->fd;
    struct ChannelMap* channelMap = evLoop->channelMap;
    if(fd >= channelMap->size)//对应的下标超出了现有数组容量
    {
        //没有足够空间存储键值对，扩容
        if(!makeMapRoom(channelMap, fd, sizeof(struct Channel*)))
        {
            return -1;
        }
    }
    //找到fd对应的数组元素位置，并存储
    if(channelMap->list[fd] == NULL)
    {
        channelMap->list[fd] = channel;
        //放入监听集合
        evLoop->dispatcher->add(channel, evLoop);
    }
    return 0;
}
//删除channel
int eventLoopRemove(struct EventLoop* evLoop, struct Channel* channel)
{
    int fd = channel->fd;
    struct ChannelMap* channelMap = evLoop->channelMap;
    if(fd >= channelMap->size)//不在Map里
    {
        return -1;
    }
    int ret = evLoop->dispatcher->remove(channel, evLoop);
    return ret;
}
//修改channel事件
int eventLoopModify(struct EventLoop* evLoop, struct Channel* channel)
{
    int fd = channel->fd;
    struct ChannelMap* channelMap = evLoop->channelMap;
    if(fd >= channelMap->size || channelMap->list[fd] == NULL)//不在Map里
    {
        return -1;
    }
    int ret = evLoop->dispatcher->modify(channel, evLoop);
    return ret;
}

//释放channel
int destroyChannel(struct EventLoop* evLoop, struct Channel* channel)
{
    //删除channelMap中channel和fd的对应关系
    evLoop->channelMap->list[channel->fd] = NULL;
    //关闭fd
    close(channel->fd);
    //释放channel
    free(channel);
    return 0;
}